/**
 * 
 */
package com.maywide.jdp.system.bean;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.metamodel.Metamodel;

import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;

import com.maywide.jdp.core.vo.Page;
import com.maywide.jdp.dao.ISQLTranslater;
import com.maywide.jdp.dao.PageQueryTemplate;
import com.maywide.jdp.dao.QueryTemplate;

/**
 * @author luoyang
 *
 */
public abstract class BaseBeanImpl {
	@PersistenceContext
	protected EntityManager em = null;

	protected void clear() {
		em.clear();
	}

	protected void close() {
		em.close();
	}

	protected boolean contains(Object obj) {
		return em.contains(obj);
	}

	protected Query createNamedQuery(String name) {
		return em.createNamedQuery(name);
	}

	protected <T> TypedQuery<T> createNamedQuery(String name, Class<T> clazz) {
		return em.createNamedQuery(name, clazz);
	}

	protected Query createNativeQuery(String name) {
		return em.createNativeQuery(name);
	}

	@SuppressWarnings({ "rawtypes" })
	protected Query createNativeQuery(String sql, Class clazz) {
		return em.createNativeQuery(sql, clazz);
	}

	protected Query createNativeQuery(String sql, String className) {
		return em.createNativeQuery(sql, className);
	}

	protected Query createQuery(String jql) {
		return em.createQuery(jql);
	}

	protected <T> TypedQuery<T> createQuery(CriteriaQuery<T> query) {
		return em.createQuery(query);
	}

	protected <T> TypedQuery<T> createQuery(String jql, Class<T> clazz) {
		return em.createQuery(jql, clazz);
	}

	protected void detach(Object obj) {
		em.detach(obj);
	}

	protected <T> T find(Class<T> clazz, Object obj) {
		return em.find(clazz, obj);
	}

	protected <T> T find(Class<T> clazz, Object obj, Map<String, Object> conditions) {
		return em.find(clazz, obj, conditions);
	}

	protected <T> T find(Class<T> clazz, Object obj, LockModeType type) {
		return em.find(clazz, obj, type);
	}

	protected <T> T find(Class<T> clazz, Object obj, LockModeType type,
			Map<String, Object> conditions) {
		return em.find(clazz, obj, type,conditions);
	}

	protected void flush() {
		em.flush();
	}

	protected CriteriaBuilder getCriteriaBuilder() {
		return em.getCriteriaBuilder();
	}

	protected Object getDelegate() {
		return em.getDelegate();
	}

	protected EntityManagerFactory getEntityManagerFactory() {
		return em.getEntityManagerFactory();
	}

	protected FlushModeType getFlushMode() {
		return em.getFlushMode();
	}

	protected LockModeType getLockMode(Object obj) {
		return em.getLockMode(obj);
	}

	protected Metamodel getMetamodel() {
		return em.getMetamodel();
	}

	protected Map<String, Object> getProperties() {
		return em.getProperties();
	}

	protected <T> T getReference(Class<T> clazz, Object obj) {
		return em.getReference(clazz, obj);
	}

	protected EntityTransaction getTransaction() {
		return em.getTransaction();
	}

	protected boolean isOpen() {
		return em.isOpen();
	}

	protected void joinTransaction() {
		em.joinTransaction();
	}

	protected void lock(Object obj, LockModeType type) {
		em.lock(obj, type);
	}

	protected void lock(Object obj, LockModeType type, Map<String, Object> map) {
		em.lock(obj, type, map);
	}

	protected <T> T merge(T obj) {
		return em.merge(obj);
	}

	protected void persist(Object obj) {
		em.persist(obj);
	}

	protected void refresh(Object obj) {
		em.refresh(obj);
	}

	protected void refresh(Object obj, Map<String, Object> map) {
		em.refresh(obj, map);
	}

	protected void refresh(Object obj, LockModeType type) {
		em.refresh(obj, type);
	}

	protected void refresh(Object obj, LockModeType type, Map<String, Object> map) {
		em.refresh(obj, type, map);
	}

	protected void remove(Object obj) {
		em.remove(obj);
	}

	protected void setFlushMode(FlushModeType type) {
		em.setFlushMode(type);
	}

	protected void setProperty(String name, Object value) {
		em.setProperty(name, value);
	}

	protected <T> T unwrap(Class<T> clazz) {
		return em.unwrap(clazz);
	}

	@SuppressWarnings("rawtypes")
	protected int executeUpdate(String hql, Map<String, Object> parameters)
			throws Exception {
		int count = 0;
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		org.hibernate.Query query = currentSession.createQuery(hql);
		
		if(parameters != null) {
			Set<String> keySet = parameters.keySet();
			for(String key : keySet) {
				Object parameter = parameters.get(key);
				if(parameter instanceof Collection)
					query.setParameterList(key, (Collection)parameter);
				else
					query.setParameter(key, parameter);
			}
		}
		count = query.executeUpdate();
		return count;
	}

	@SuppressWarnings("rawtypes")
	protected List executeQuery(String hql, Map<String, Object> conditions,Map<String,Object> parameters)
			throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			if(conditions != null) {
				Set<String> keySet = conditions.keySet();
				for(String key : keySet) {
					Object condition = conditions.get(key);
					if(condition == null) {
						currentSession.enableFilter(key);
						continue;
					}
					if(condition instanceof Collection)
						currentSession.enableFilter(key).setParameterList(key, (Collection) condition);
					else if(condition.getClass().isArray())
						currentSession.enableFilter(key).setParameterList(key, (Object[]) condition);
					else
						currentSession.enableFilter(key).setParameter(key, condition);
				}
			}
			
			org.hibernate.Query query = currentSession.createQuery(hql);
			
			if(parameters != null) {
				Set<String> keySet = parameters.keySet();
				for(String key : keySet) {
					Object parameter = parameters.get(key);
					query.setParameter(key, parameter);
				}
			}
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}

	@SuppressWarnings("rawtypes")
	protected List executeListQuery(QueryTemplate template,
			Map<String, Object> conditions, Map<String, Object> parameters)
			throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			if(conditions != null) {
				Set<String> keySet = conditions.keySet();
				for(String key : keySet) {
					Object condition = conditions.get(key);
					if(condition == null) {
						currentSession.enableFilter(key);
						continue;
					}
					if(condition instanceof Collection)
						currentSession.enableFilter(key).setParameterList(key, (Collection) condition);
					else if(condition.getClass().isArray())
						currentSession.enableFilter(key).setParameterList(key, (Object[]) condition);
					else
						currentSession.enableFilter(key).setParameter(key, condition);
				}
			}
			
			String queryString = template.getQueryString();
			StringBuffer buf = new StringBuffer(queryString);
			String sort = template.getSort();
			if(sort != null)
				buf.append(" order by ").append(sort);
			String dir = template.getDir();
			if(dir != null)
				buf.append(" ").append(dir);
			String hql = buf.toString();
			
			org.hibernate.Query query = currentSession.createQuery(hql);
	
			if(parameters != null) {
				Set<String> keySet = parameters.keySet();
				for(String key : keySet) {
					Object parameter = parameters.get(key);
					query.setParameter(key, parameter);
				}
			}
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}

	@SuppressWarnings("rawtypes")
	protected List executeListQuery(QueryTemplate template,
			Map<String, Object> conditions, Map<String, Object> parameters,
			Class clazz) throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			if(conditions != null) {
				Set<String> keySet = conditions.keySet();
				for(String key : keySet) {
					Object condition = conditions.get(key);
					if(condition == null) {
						currentSession.enableFilter(key);
						continue;
					}
					if(condition instanceof Collection)
						currentSession.enableFilter(key).setParameterList(key, (Collection) condition);
					else if(condition.getClass().isArray())
						currentSession.enableFilter(key).setParameterList(key, (Object[]) condition);
					else
						currentSession.enableFilter(key).setParameter(key, condition);
				}
			}
			
			String queryString = template.getQueryString();
			StringBuffer buf = new StringBuffer(queryString);
			String sort = template.getSort();
			if(sort != null)
				buf.append(" order by ").append(sort);
			String dir = template.getDir();
			if(dir != null)
				buf.append(" ").append(dir);
			String hql = buf.toString();
			
			org.hibernate.Query query = currentSession.createQuery(hql);
	
			if(parameters != null) {
				Set<String> keySet = parameters.keySet();
				for(String key : keySet) {
					Object parameter = parameters.get(key);
					query.setParameter(key, parameter);
				}
			}
			
			query.setResultTransformer(Transformers.aliasToBean(clazz));
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}

	@SuppressWarnings("rawtypes")
	protected Page executePageQuery(PageQueryTemplate template,Map<String, Object> conditions,Map<String, Object> parameters) throws Exception {
		Page page = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			if(conditions != null) {
				Set<String> keySet = conditions.keySet();
				for(String key : keySet) {
					Object condition = conditions.get(key);
					if(condition == null) {
						currentSession.enableFilter(key);
						continue;
					}
					if(condition instanceof Collection)
						currentSession.enableFilter(key).setParameterList(key, (Collection) condition);
					else if(condition.getClass().isArray())
						currentSession.enableFilter(key).setParameterList(key, (Object[]) condition);
					else
						currentSession.enableFilter(key).setParameter(key, condition);
				}
			}
			
			String queryString = template.getQueryString();
			StringBuffer buf = new StringBuffer(queryString);
			String sort = template.getSort();
			if(sort != null)
				buf.append(" order by ").append(sort);
			String dir = template.getDir();
			if(dir != null)
				buf.append(" ").append(dir);
			String hql = buf.toString();
			
			org.hibernate.Query query = currentSession.createQuery(hql);
	
			if(parameters != null) {
				Set<String> keySet = parameters.keySet();
				for(String key : keySet) {
					Object parameter = parameters.get(key);
					query.setParameter(key, parameter);
				}
			}
			
			int first = template.getFirst();
			int limit = template.getLimit();
			query.setFirstResult(first);
			if(limit >0)
				query.setMaxResults(limit);
			List data = query.list();
			if(data != null && !data.isEmpty()) {
				String countQueryString = template.getCountQueryString();
				org.hibernate.Query countQuery = currentSession.createQuery(countQueryString);
				if(parameters != null)
					countQuery.setProperties(parameters);
				long total = (Long)countQuery.uniqueResult();
				page = new Page(total,data);
			} else {
				page = new Page(0,new ArrayList());
			}
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return page;
	}

	@SuppressWarnings({ "rawtypes" })
	protected Page executePageQuery(PageQueryTemplate template,Map<String, Object> conditions,Map<String, Object> parameters,Class clazz) throws Exception {
		Page page = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			if(conditions != null) {
				Set<String> keySet = conditions.keySet();
				for(String key : keySet) {
					Object condition = conditions.get(key);
					if(condition == null) {
						currentSession.enableFilter(key);
						continue;
					}
					if(condition instanceof Collection)
						currentSession.enableFilter(key).setParameterList(key, (Collection) condition);
					else if(condition.getClass().isArray())
						currentSession.enableFilter(key).setParameterList(key, (Object[]) condition);
					else
						currentSession.enableFilter(key).setParameter(key, condition);
				}
			}
			
			String queryString = template.getQueryString();
			StringBuffer buf = new StringBuffer(queryString);
			String sort = template.getSort();
			if(sort != null)
				buf.append(" order by ").append(sort);
			String dir = template.getDir();
			if(dir != null)
				buf.append(" ").append(dir);
			String hql = buf.toString();
			
			org.hibernate.Query query = currentSession.createQuery(hql);
	
			if(parameters != null) {
				Set<String> keySet = parameters.keySet();
				for(String key : keySet) {
					Object parameter = parameters.get(key);
					query.setParameter(key, parameter);
				}
			}
			
			int first = template.getFirst();
			int limit = template.getLimit();
			query.setFirstResult(first);
			if(limit >0)
			query.setMaxResults(limit);
			query.setResultTransformer(Transformers.aliasToBean(clazz));
			List data = query.list();
			if(data != null && !data.isEmpty()) {
				String countQueryString = template.getCountQueryString();
				org.hibernate.Query countQuery = currentSession.createQuery(countQueryString);
				if(parameters != null)
					countQuery.setProperties(parameters);
				long total = (Long)countQuery.uniqueResult();
				page = new Page(total,data);
			} else {
				page = new Page(0,new ArrayList());
			}
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return page;
	}

	@SuppressWarnings("rawtypes")
	protected List executeNativeQuery(String sql, Map<String, Object> parameters,
			Class clazz) throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			SQLQuery query = currentSession.createSQLQuery(sql);
			
			if(parameters != null)
				query.setProperties(parameters);
			
			if(clazz != null)
				query.addEntity(clazz);
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}

	@SuppressWarnings("rawtypes")
	protected Page executeNativePageQuery(String sql,String countSQL, Map<String, Object> parameters,
			Class clazz) throws Exception {
		Page page = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			SQLQuery query = currentSession.createSQLQuery(sql);
			
			if(parameters != null)
				query.setProperties(parameters);
			
			if(clazz != null)
				query.addEntity(clazz);
			List data = query.list();
			
			if(data != null && !data.isEmpty()) {
				SQLQuery countSQLQuery = currentSession.createSQLQuery(countSQL);
				int total = (Integer)countSQLQuery.uniqueResult();
				page = new Page(total,data);				
			}
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return page;
	}

	@SuppressWarnings("rawtypes")
	protected List executeNativeQuery(String sql, Map<String, Object> parameters,
			Class clazz,String resultMapName) throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			SQLQuery query = currentSession.createSQLQuery(sql);
			
			if(parameters != null)
				query.setProperties(parameters);
			
			query.setResultSetMapping(resultMapName);
			query.setResultTransformer(Transformers.aliasToBean(clazz));
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}

	@SuppressWarnings("rawtypes")
	protected Page executeNativePageQuery(String sql,String countSQL, Map<String, Object> parameters,
			Class clazz,String resultMapName) throws Exception {
		Page page = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			SQLQuery query = currentSession.createSQLQuery(sql);
			
			if(parameters != null)
				query.setProperties(parameters);
			
			query.setResultTransformer(Transformers.aliasToBean(clazz));
			query.setResultSetMapping(resultMapName);
			List data = query.list();
			
			if(data != null && !data.isEmpty()) {
				SQLQuery countSQLQuery = currentSession.createSQLQuery(countSQL);
				int total = (Integer)countSQLQuery.uniqueResult();
				page = new Page(total,data);				
			}
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return page;
	}

	@SuppressWarnings("rawtypes")
	protected List executeNamedQuery(String name, Map<String, Object> conditions,
			Map<String, Object> parameters) throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			if(conditions != null) {
				Set<String> keySet = conditions.keySet();
				for(String key : keySet) {
					Object condition = conditions.get(key);
					if(condition == null) {
						currentSession.enableFilter(key);
						continue;
					}
					if(condition instanceof Collection)
						currentSession.enableFilter(key).setParameterList(key, (Collection) condition);
					else if(condition.getClass().isArray())
						currentSession.enableFilter(key).setParameterList(key, (Object[]) condition);
					else
						currentSession.enableFilter(key).setParameter(key, condition);
				}
			}
			
			org.hibernate.Query query = currentSession.getNamedQuery(name);
			
			if(parameters != null) {
				Set<String> keySet = parameters.keySet();
				for(String key : keySet) {
					Object parameter = parameters.get(key);
					query.setParameter(key, parameter);
				}
			}
	
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}

	@SuppressWarnings("rawtypes")
	protected List executeNamedQuery(String name, Map<String, Object> conditions,
			Map<String, Object> parameters, Class clazz) throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			if(conditions != null) {
				Set<String> keySet = conditions.keySet();
				for(String key : keySet) {
					Object condition = conditions.get(key);
					if(condition == null) {
						currentSession.enableFilter(key);
						continue;
					}
					if(condition instanceof Collection)
						currentSession.enableFilter(key).setParameterList(key, (Collection) condition);
					else if(condition.getClass().isArray())
						currentSession.enableFilter(key).setParameterList(key, (Object[]) condition);
					else
						currentSession.enableFilter(key).setParameter(key, condition);
				}
			}
			
			org.hibernate.Query query = currentSession.getNamedQuery(name);
			
			if(parameters != null) {
				Set<String> keySet = parameters.keySet();
				for(String key : keySet) {
					Object parameter = parameters.get(key);
					query.setParameter(key, parameter);
				}
			}
			
			query.setResultTransformer(Transformers.aliasToBean(clazz));
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}

	@SuppressWarnings({ "rawtypes" })
	protected List executeNamedNativeQuery(String name,
			Map<String, Object> parameters, ISQLTranslater translater, Class clazz,String resultMapName)
			throws Exception {
		List list = null;
		
		Session currentSession = (Session)em.getDelegate();
		if(!currentSession.isOpen()) {
			SessionFactory sessionFactory = ((Session)em.getDelegate()).getSessionFactory();
			currentSession = sessionFactory.openSession();
		}
		
		try {
			String queryString = currentSession.getNamedQuery(name).getQueryString();
			String sql = translater.execute(queryString, parameters);
			SQLQuery query = currentSession.createSQLQuery(sql);
			
			if(parameters != null)
				query.setProperties(parameters);
			
			query.setResultTransformer(Transformers.aliasToBean(clazz));
			query.setResultSetMapping(resultMapName);
			list = query.list();
		} catch(Exception e) {
			throw e;
		} finally {
			if(currentSession.isOpen())
				currentSession.close();
		}
		return list;
	}
}
